#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include "utils.h"


#define NPROS 4

// 本例演示MPI通信子相关的API，主要包括:
int main(int argc, char** argv) {
    int rank, size, r, send, recv;

    int ranks1[2] = {0, 1},       ranks2[2] = {2, 3};
    int rnks1[8]  = {0, 1, 2, 3}, rnks2[4]  = {0};

    int rangein[1][3] = {{0, 1, 1}};
    int rangeex[1][3] = {{0, 1, 1}};
    
    MPI_Group grp_wld, grp_cty;
    MPI_Group grp1, grp2;

    MPI_Comm  comm_cty;
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    send = rank;

    if (size != NPROS) {
        ERROR("This example must be run with %d processes\n", NPROS);
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    MPI_Comm_group(MPI_COMM_WORLD, &grp_wld);
    if (rank < NPROS/2) {
        MPI_Group_incl(grp_wld, 2,  ranks1, &grp_cty);
    } else {
         MPI_Group_incl(grp_wld, 2, ranks2, &grp_cty);
    }

    MPI_Comm_create(MPI_COMM_WORLD, grp_cty, &comm_cty);

    // enum {
    //     MPI_IDENT,      // 0
    //     MPI_CONGRUENT,
    //     MPI_SIMILAR,
    //     MPI_UNEQUAL
    // };
    MPI_Group_compare(grp_wld, grp_cty, &r);
    // INFO(">> rank: %d, compare result: %d;\n", rank, r); // 输出为MPI_UNEQUAL=3


    MPI_Group_translate_ranks(grp_wld, 4, rnks1, grp_cty, rnks2);
    // [INFO] >> rank: 1 [0 1 -32766 -32766];
    // [INFO] >> rank: 2 [-32766 -32766 0 1];
    // [INFO] >> rank: 3 [-32766 -32766 0 1];
    // [INFO] >> rank: 0 [0 1 -32766 -32766];
    // INFO(">> rank: %d [%d %d %d %d];\n", rank, rnks2[0], rnks2[1],rnks2[2],rnks2[3]);

    MPI_Allreduce(&send, &recv, 1, MPI_INT, MPI_SUM, comm_cty);
    // INFO(">> rank: %d, reduce result: %d;\n", rank, recv);


    //! rank =0,1中，grp_cty包含了0,1, rank =2,3中，grp_cty包含了2,3;
    //! rank=0,1中的3中，grp_cty包含了2与rank =2,3中的3中，grp_cty包含了2值不同;
    //! rank=[0,1]的grp_cty只包含了原始前两个线程
    //! rank=[2,3]的grp_cty只包含了原始后两个线程

    //! rank=[0,1]的grp1包含了原始的前两个线程,rank=[2,3]的grp1包含了原始的后两个线程
    MPI_Group_range_incl(grp_cty, 1, rangein, &grp1); 

    //! rank=[0,1,2,3]的grp2不包含任何线程
    MPI_Group_range_excl(grp_cty, 1, rangeex, &grp2);  
    MPI_Barrier(MPI_COMM_WORLD);

    int rnk1, rnk2, sz1, sz2;
    MPI_Group_rank(grp1, &rnk1);
    MPI_Group_rank(grp2, &rnk2);
    MPI_Group_size(grp1, &sz1);
    MPI_Group_size(grp2, &sz2);
    INFO(">> rank: %d, rank 1: %d, rank 2: %d size = {%d, %d};\n", rank, rnk1, rnk2, sz1, sz2);


    MPI_Comm_free(&comm_cty);

    MPI_Finalize();
    return 0;
}